"""
@File    :   service.py
@Time    :   2024/04/24 21:40:31
@Author  :   Qrj
@Email   :   923207736@qq.com
@description   :   OAuth2客户端模式认证相关业务逻辑
"""

from redis.asyncio import Redis
from sqlalchemy.ext.asyncio import AsyncSession

from src.business.admin.system.oauth2.auth.client_credentials.schemas.validate import (
    ClientCredentialsCreateDoubleTokenValidateSchema,
)
from src.business.admin.system.oauth2.auth.enums import OAuth2GrantTypeEnum
from src.business.admin.system.oauth2.client.schemas.out import (
    Oauth2ClientCompleteOutSchema,
)
from src.business.admin.system.oauth2.client.service import Oauth2ClientService
from src.business.admin.system.oauth2.token.schemas.out import (
    DoubleTokenCompleteOutSchema,
)
from src.business.admin.system.oauth2.token.schemas.validate import (
    DoubleTokenCreateValidateSchema,
)
from src.business.admin.system.oauth2.token.service import TokenService
from src.business.admin.system.tenant.tenant.schemas.out import TenantCompleteOutSchema
from src.business.admin.system.tenant.tenant.service import TenantService


class ClientCredentialsService:
    """OAuth2客户端模式认证业务逻辑类"""

    @staticmethod
    async def create_client_credentials_double_token(
        db_session: AsyncSession,
        token_redis_pool: Redis,
        create_schema: ClientCredentialsCreateDoubleTokenValidateSchema,
    ) -> DoubleTokenCompleteOutSchema:
        """创建客户端模式的双Token

        Args:
            db_session (AsyncSession): 数据库连接池
            token_redis_pool (Redis): Token的redis缓存连接池
            create_schema (ClientCredentialsCreateDoubleTokenValidateSchema): 创建所需的参数

        Returns:
            DoubleTokenCompleteOutSchema: 双Token数据
        """
        # 验证租户是否存在
        tenant: TenantCompleteOutSchema = await TenantService.get_tenant_use_id(
            db_session, create_schema.tenant_id
        )
        # 验证OAuth2客户端是否存在
        oauth2_client: Oauth2ClientCompleteOutSchema = (
            await Oauth2ClientService.get_oauth2_client_use_client_id(
                db_session,
                create_schema.tenant_id,
                create_schema.oauth2_client_client_id,
            )
        )
        # 验证客户端密钥是否正确
        Oauth2ClientService.validate_oauth2_client_secret(
            oauth2_client.client_secret,
            create_schema.oauth2_client_client_secert,
            field_name="oauth2_client_client_secert",
        )
        # 验证是否允许客户端使用当前授权模式
        Oauth2ClientService.validate_oauth2_client_authorized_grant_type(
            oauth2_client.authorized_grant_types, OAuth2GrantTypeEnum.client_credentials
        )
        # 生成token的授权范围(自动赋予的oauth2授权范围 + 用户选择的在oauth2授权范围的权限)
        token_scopes = Oauth2ClientService.generate_scopes(
            oauth2_client.scopes,
            oauth2_client.auto_approve_scopes,
            create_schema.required_scopes,
        )
        # 客户端模式的双Token没有用户信息, 不占用用户的登录名额
        create_double_token_schema = DoubleTokenCreateValidateSchema(
            tenant_id=tenant.id,
            tenant_is_system=tenant.is_system,
            tenant_pakcage_id=tenant.tenant_package_id,
            oauth2_client_id=oauth2_client.id,
            oauth2_grant_type=OAuth2GrantTypeEnum.client_credentials.value,
            access_token_expiration_seconds=oauth2_client.access_token_expiration_seconds,
            refresh_token_expiration_seconds=oauth2_client.refresh_token_expiration_seconds,
            oauth2_scopes=token_scopes,
            occupation_of_login_quota=False,
        )
        double_token = await TokenService.create_double_token(
            db_session, token_redis_pool, create_double_token_schema
        )
        return double_token
